# _*_ coding:utf-8 _*_
# @File  : ruizy_user_menu.py
# @Time  : 2022-01-12  14:24
# @Author: zizle
import datetime

from fastapi import APIRouter, Body, Header, Query
from pydantic import BaseModel, validator

from db import FAConnection
from v1_all_api import constant
from v1_all_api.all_response import AllResponse
from v1_all_api.all_utils import datetime_utils, data_utils
from hutool import security
from configs import RUIZHI_MANAGERS

user_menu_api = APIRouter()


# class UserMenuItem(BaseModel):
#     user_id: conint(ge=1)
#     menu_id: conint(ge=1)
#     expire: datetime_parse.date


# 角色功能权限
class RoleMenuItem(BaseModel):
    role_code: int
    menu_code: int
    expire: str

    @validator('expire')
    def validate_start_date(cls, value):
        if not datetime_utils.auth_datetime_string(str(value), f='%Y-%m-%d'):
            raise ValueError('expire,使用YYYY-MM-DD')
        return value


# 私人功能权限
class PrivateMenuItem(BaseModel):
    user_id: int
    menu_code: int
    expire: str

    @validator('expire')
    def validate_start_date(cls, value):
        if not datetime_utils.auth_datetime_string(str(value), f='%Y-%m-%d'):
            raise ValueError('expire,使用YYYY-MM-DD')
        return value


# @user_menu_api.post('/userMenuAccesses/')  # 创建用户访问的功能权限
# async def create_user_menu(ruizy_token: str = Header(...), user_menu: UserMenuItem = Body(...)):
#     person = security.decrypt_access_token(ruizy_token)
#     if not person:
#         return AllResponse.no_authorization()
#     if not security.operator_is_super_admin(person):
#         return AllResponse.forbidden_error()
#     user_menu.expire = user_menu.expire.strftime('%Y%m%d')
#     db_conn = FAConnection()
#     # 用户是admin或者菜单类型是vip的，无需分配
#     auth_sql = """
#         SELECT role As r FROM ruizy_user WHERE id=%s
#         UNION
#         SELECT category As r FROM ruizy_menu WHERE id=%s;
#     """
#     auth_prm = (user_menu.user_id, user_menu.menu_id)
#     auth_data = db_conn.query(auth_sql, param=auth_prm, keep_conn=True)
#
#     if len(auth_data) == 1:
#         user_role = menu_category = auth_data[0]['r']
#     else:
#         user_role, menu_category = auth_data[0]['r'], auth_data[1]['r']
#
#     if user_role == 'admin' or menu_category in ['free', 'vip']:
#         db_conn.close()
#         return AllResponse.no_do_anything(msg='admin用户或free、vip菜单无需进行此操作!')
#
#     # 查询是否存在，存在更新到期时间，不存在新增
#     user_menu_obj = db_conn.query('SELECT id FROM ruizy_user_menu WHERE user_id=%s AND menu_id=%s;',
#                                   param=[user_menu.user_id, user_menu.menu_id],
#                                   fetchone=True, keep_conn=True)[0]
#     if not user_menu_obj:
#         op_sql = 'INSERT INTO ruizy_user_menu (user_id,menu_id,expire) VALUES (%s,%s,%s);'
#         op_params = [user_menu.user_id, user_menu.menu_id, user_menu.expire]
#     else:
#         op_sql = 'UPDATE ruizy_user_menu SET expire=%s WHERE user_id=%s AND menu_id=%s;'
#         op_params = [user_menu.expire, user_menu.user_id, user_menu.menu_id]
#     _, success = db_conn.execute(op_sql, param=op_params)
#     if success:
#         return AllResponse.operate_successfully()
#     else:
#         return AllResponse.server_error()
#
#
# @user_menu_api.get('/userMenuAccesses/')  # 通过ID获取用户的功能权限
# async def get_user_menu(ruizy_token: str = Header(...), uid: int = Query(..., ge=1)):
#     person = security.decrypt_access_token(ruizy_token)
#     if not person:
#         return AllResponse.no_authorization()
#     if not security.operator_is_super_admin(person):
#         return AllResponse.forbidden_error()
#     db_conn = FAConnection()
#     # 查询用户信息
#     user_info_sql = "SELECT id,ruizy_code,nickname,phone,expire,role,is_analyst,expire FROM ruizy_user WHERE id=%s;"
#     user_obj = db_conn.query(user_info_sql, param=[uid], keep_conn=True, fetchone=True)[0]
#     if not user_obj:
#         return AllResponse.server_no_content(msg='查询的用户不存在！')
#     # 查询用户的菜单权限及其有效期
#     sql = """
#          SELECT m.id,m.name_zh,m.category,m.parent_id,m.sorted,m.hidden,m.is_active,
#          um.expire
#          FROM ruizy_menu As m
#          LEFT JOIN ruizy_user_menu As um ON um.menu_id=m.id AND um.user_id=%s
#          ORDER BY m.id,m.sorted;
#     """
#     records = db_conn.query(sql, param=[uid])
#     today = datetime.date.today().strftime('%Y-%m-%d')
#     for row in records:
#         row['accessible'] = False
#         if row['expire'] and row['expire'].strftime('%Y-%m-%d') >= today:
#             row['accessible'] = True
#     # 转为tree结构
#     menu_tree = utils.list2tree(records, 0)
#     response_data = {
#         'menus': menu_tree,
#         'user': user_obj
#     }
#     return AllResponse.operate_successfully(data=response_data)

# 处理菜单数据
def handle_menu_meta(m):
    if m['parent_code'] == 0:  # parent_code=0是顶级navbar，不用设置这些
        return m
    m['meta'] = {
        'title': m['menu_name'],
        'icon': m['icon'],
        'permissions': ['free']  # 控制菜单的访问权限，现在没有用，跟token或去信息时返回的permission一致即可
    }
    m['name'] = m['vue_name']
    del m['vue_name']
    del m['icon']
    if not m['redirect']:
        del m['redirect']
    return m


# 返回所有菜单都能访问的权限
def all_menu_access(person_id):
    sql = """
        SELECT menu.id,menu.menu_code,menu.menu_name,menu.parent_code,menu.vue_name,menu.component,
          menu.icon,menu.path,menu.redirect,menu.hidden,menu.sorted,menu.is_ruizhi
        FROM ruizy_menu As menu WHERE menu.is_active=1 ORDER BY menu.id,menu.sorted
    """
    with FAConnection() as cursor:
        cursor.execute(sql)
        menu_list = list(cursor.fetchall())
    for m in menu_list:
        m['no_edit'] = True
        m['is_access'] = True
        m['hidden_zh'] = '是' if m['hidden'] else '否'
        m['expire'] = '20991231'
    menu_list.sort(key=lambda x: (x['sorted'], x['id']))  # 排序
    menu_list = list(map(handle_menu_meta, menu_list))
    if person_id not in RUIZHI_MANAGERS:
        menu_list = list(filter(lambda x: not x['is_ruizhi'], menu_list))
    # 转为tree结构
    menu_tree = data_utils.list2tree(menu_list, pkey='parent_code', ckey='menu_code', fvalue='0')
    return AllResponse.operate_successfully(data=menu_tree)


# 通过角色(系统角色和身份角色)获取用户功能权限
@user_menu_api.get('/roleMenus/')
def get_role_menus(ruizy_token: str = Header(...), role: int = Query(...)):
    person = security.decrypt_access_token(ruizy_token)
    if not person:
        return AllResponse.no_authorization()
    if role == constant.DEVELOPER or role == constant.ADMIN_ROLE_CODE:
        return all_menu_access(person_id=person['uid'])
    # 查询角色的菜单
    sql = """
        SELECT menu.id,menu.menu_code,menu.menu_name,menu.vue_name,menu.parent_code,menu.sorted,menu.hidden,
          role.id as rm_id,role.role_code as rm_rcode,role.menu_code as rm_mcode,role.expire
        FROM ruizy_menu As menu
        LEFT JOIN ruizy_role_menu As role ON menu.menu_code=role.menu_code AND role.role_code=%s
        WHERE menu.is_active=1 ORDER BY menu.id,menu.sorted;
    """
    with FAConnection() as cursor:
        cursor.execute(sql, [role])
        menu_list = list(cursor.fetchall())
    today = datetime_utils.today()
    for m in menu_list:
        m['is_access'] = True if m['rm_id'] and m['expire'].strftime('%Y%m%d') > today else False
        m['hidden_zh'] = '是' if m['hidden'] else '否'
    menu_list.sort(key=lambda x: (x['sorted'], x['id']))  # 排序
    # 转为tree结构
    menu_tree = data_utils.list2tree(menu_list, pkey='parent_code', ckey='menu_code', fvalue='0')
    return AllResponse.operate_successfully(data=menu_tree)


# 设定角色的功能权限
@user_menu_api.post('/roleMenus/')
def set_role_menus(ruizy_token: str = Header(...), rm: RoleMenuItem = Body(...)):
    person = security.decrypt_access_token(ruizy_token)
    if not person:
        return AllResponse.no_authorization()
    if not security.operator_is_manager(person):
        return AllResponse.forbidden_error()
    # 查询记录是否存在，存在更新，不存在增加
    with FAConnection() as cursor:
        cursor.execute('SELECT id,role_code,menu_code,expire FROM ruizy_role_menu WHERE role_code=%s AND menu_code=%s LIMIT 1;',
                       [rm.role_code, rm.menu_code])
        rm_obj = cursor.fetchone()
        if rm_obj:
            # 更新
            sql = "UPDATE ruizy_role_menu SET expire=%s WHERE id=%s LIMIT 1;"
            prm = [rm.expire, rm_obj['id']]
        else:
            # 新增
            sql = 'INSERT INTO ruizy_role_menu (role_code,menu_code,expire) VALUES (%s,%s,%s);'
            prm = [rm.role_code, rm.menu_code, rm.expire]
        cursor.execute(sql, prm)
    return AllResponse.operate_successfully()


# 特别功能权限
@user_menu_api.get('/privateMenus/')
def get_private_menus(ruizy_token: str = Header(...), uid: int = Query(None)):
    """没有uid时获取的是token自身的菜单权限"""
    person = security.decrypt_access_token(ruizy_token)
    if not person:
        return AllResponse.no_authorization()
    if uid:
        # 查询的是别的用户
        person['uid'] = uid
        if not security.operator_is_manager(person):  # 不是管理员
            return AllResponse.forbidden_error()
        # 查询别的用户的role_code与out_role
        with FAConnection() as cursor:
            cursor.execute('SELECT id,role_code,out_role FROM ruizy_user WHERE id=%s LIMIT 1;', [uid])
            o_user = cursor.fetchone()
        if not o_user:
            return AllResponse.server_no_content(msg='用户不存在.')
        # 设置查询的对象
        person['role_code'] = o_user['role_code']
        person['out_role'] = o_user['out_role']
        person['uid'] = o_user['id']
    if security.operator_is_super_admin(person):
        return all_menu_access(person_id=person['uid'])
    user_sql = """
        SELECT m.id,m.menu_code,m.menu_name,m.parent_code,m.vue_name,m.sorted,m.hidden,m.hidden,m.sorted,
          u.expire,u.id as um_id,u.menu_code as um_menu_code 
        FROM ruizy_menu As m 
        LEFT JOIN ruizy_user_menu As u ON m.menu_code=u.menu_code AND u.user_id=%s 
        WHERE m.is_active=1 ORDER BY m.id,m.sorted;
    """
    user_prm = [person['uid']]
    with FAConnection() as cursor:
        cursor.execute(user_sql, user_prm)  # 用户指定权限
        menu_list = list(cursor.fetchall())
    today = datetime_utils.today()
    for m in menu_list:
        m['is_access'] = True if m['um_id'] and m['expire'].strftime('%Y%m%d') > today else False
        m['hidden_zh'] = '是' if m['hidden'] else '否'
    menu_list.sort(key=lambda x: (x['sorted'], x['id']))  # 排序
    # 转为tree结构
    menu_tree = data_utils.list2tree(menu_list, pkey='parent_code', ckey='menu_code', fvalue='0')
    return AllResponse.operate_successfully(data=menu_tree)


# 设定特别的功能权限
@user_menu_api.post('/privateMenus/')
def set_private_menus(ruizy_token: str = Header(...), um: PrivateMenuItem = Body(...)):
    person = security.decrypt_access_token(ruizy_token)
    if not person:
        return AllResponse.no_authorization()
    if not security.operator_is_manager(person):
        return AllResponse.forbidden_error()
    # 查询记录是否存在，存在更新，不存在增加
    with FAConnection() as cursor:
        cursor.execute('SELECT id,user_id,menu_code,expire FROM ruizy_user_menu WHERE user_id=%s AND menu_code=%s LIMIT 1;',
                       [um.user_id, um.menu_code])
        um_obj = cursor.fetchone()
        if um_obj:
            # 更新
            sql = "UPDATE ruizy_user_menu SET expire=%s WHERE id=%s LIMIT 1;"
            prm = [um.expire, um_obj['id']]
        else:
            # 新增
            sql = 'INSERT INTO ruizy_user_menu (user_id,menu_code,expire) VALUES (%s,%s,%s);'
            prm = [um.user_id, um.menu_code, um.expire]
        cursor.execute(sql, prm)
    return AllResponse.operate_successfully()


# 获取指定用户的功能权限(综合权限结果)
@user_menu_api.get('/userMenus/')
def get_user_menus(ruizy_token: str = Header(...), uid: int = Query(None)):
    """没有uid时获取的是token自身的菜单权限"""
    person = security.decrypt_access_token(ruizy_token)
    if not person:
        return AllResponse.no_authorization()
    if security.operator_is_super_admin(person):
        return all_menu_access(person_id=person['uid'])
    if uid:
        # 查询的是别的用户
        person['uid'] = uid
        if not security.operator_is_manager(person):  # 不是管理员
            return AllResponse.forbidden_error()
        # 查询别的用户的role_code与out_role
        with FAConnection() as cursor:
            cursor.execute('SELECT id,role_code,out_role FROM ruizy_user WHERE id=%s LIMIT 1;', [uid])
            o_user = cursor.fetchone()
        if not o_user:
            return AllResponse.server_no_content(msg='用户不存在.')
        # 设置查询的对象
        person['role_code'] = o_user['role_code']
        person['out_role'] = o_user['out_role']
        person['uid'] = o_user['id']
    # 查询角色权限菜单
    role_sql = """
        SELECT m.id,m.menu_code,m.menu_name,m.parent_code,m.category,m.vue_name,m.component,m.icon,m.path,
          m.redirect,m.hidden,m.sorted,m.is_ruizhi,
          ro.expire,ro.id as auth_id 
        FROM ruizy_menu As m 
        LEFT JOIN ruizy_role_menu As ro ON m.menu_code=ro.menu_code AND ro.role_code=%s 
        WHERE m.is_active=1
        ORDER BY m.sorted,m.id;
    """
    # 指定权限菜单
    user_sql = """
        SELECT m.id,m.menu_code,m.menu_name,m.parent_code,m.category,m.vue_name,m.component,m.icon,m.path,
          m.redirect,m.hidden,m.sorted,m.is_ruizhi,
          u.expire,u.id as auth_id 
        FROM ruizy_menu As m 
        LEFT JOIN ruizy_user_menu As u ON m.menu_code=u.menu_code AND u.user_id=%s 
        WHERE m.is_active=1
        ORDER BY m.sorted,m.id;
    """
    user_prm = [person['uid']]
    with FAConnection() as cursor:
        cursor.execute(role_sql, [person['role_code']])  # 系统角色权限
        sys_role_menus = list(cursor.fetchall())
        cursor.execute(role_sql, [person['out_role']])  # 身份角色权限
        out_role_menus = list(cursor.fetchall())
        cursor.execute(user_sql, user_prm)  # 用户指定权限
        user_menus = list(cursor.fetchall())
    # 三个权限合并（系统角色-身份角色-个人取有效层,有效期会覆盖）
    final_menus = []
    today = datetime_utils.today()
    for rm, om, um in zip(sys_role_menus, out_role_menus, user_menus):
        o_menu = {**rm}
        if not rm['id'] == om['id'] == um['id']:
            final_menus = []
            break
        is_access = False
        if rm['auth_id'] and rm['expire'].strftime('%Y%m%d') >= today:
            is_access = True
            o_menu['expire'] = rm['expire'].strftime('%Y%m%d')
        if om['auth_id'] and om['expire'].strftime('%Y%m%d') >= today:
            is_access = True
            o_menu['expire'] = om['expire'].strftime('%Y%m%d')
        if um['auth_id'] and um['expire'].strftime('%Y%m%d') >= today:
            is_access = True
            o_menu['expire'] = um['expire'].strftime('%Y%m%d')
        if is_access:
            final_menus.append(o_menu)
    # 排序，转为tree返回
    final_menus.sort(key=lambda x: (x['sorted'], x['id']))  # 排序
    # 去除非瑞智管理者的瑞智管理菜单
    if person['uid'] not in RUIZHI_MANAGERS:
        final_menus = list(filter(lambda x: not x['is_ruizhi'], final_menus))
    final_menus = list(map(handle_menu_meta, final_menus))
    menus = data_utils.list2tree(final_menus, pkey='parent_code', ckey='menu_code', fvalue='0')
    return AllResponse.operate_successfully(data=menus)
